package com.ljw.spring.annotation.conf;

/**
 * @FileName ConfigOfBeanLifeCycle
 * @Description TODO bean的生命周期 的配置类
 * @Author ljw
 * @Date 2021/2/2 1:40
 * @Version 1.0
 */

import com.ljw.spring.annotation.bean.*;
import com.ljw.spring.annotation.condition.LinuxCondition;
import com.ljw.spring.annotation.condition.WindowsCondition;
import com.ljw.spring.annotation.filter.MyTypeFilter;
import com.ljw.spring.annotation.service.UserService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

/**IOC容器就是缓存了bean实例的map对象
 * IOC容器管理bean的生命周期: 创建(默认通过无参构造函数)----初始化-----销毁
 *  1. 创建bean(默认通过无参构造函数创建)。bean创建成功指：属性设置完毕
 *          单例：在IOC容器启动时就创建bean，IOC容器只管理单实例的bean；
 *          多例：在每次需要bean时再创建，IOC容器不会管理多实例的bean。
 *  2. 为 bean 的属性设置值和对其他 bean 引用（调用 set 方法）
 *  3. 把 bean 实例传递 到bean 后置处理器BeanPostProcessor的方法 postProcessBeforeInitialization
 *  4. 调用 bean 的初始化的方法（需要进行配置初始化的方法）
 *  5. 把 bean 实例传递 到bean 后置处理器BeanPostProcessor的方法 postProcessAfterInitialization
 *  6. bean 可以使用了（对象获取到了）
 *  7. 当IOC容器关闭时候，调用 bean 的销毁的方法（需要进行配置销毁的方法）。
 *          （1）当IOC容器关闭时候，多实例的bean：IOC容器不会管理多实例的bean，不会自动执行销毁方法
 *          （2）当IOC容器关闭时候，单实例的bean：IOC容器只管理单实例的bean，会自动执行销毁方法
 *
 * IOC容器管理bean的生命周期之 初始化 和 销毁 有3种方式：
 *      1. 通过@Bean指定初始化和销毁方法
 *      2. bean初始化：让bean实现InitializingBean接口，重写afterPropertiesSet()方法，定义bean创建成功并属性赋值后bean的初始化逻辑
 *         bean销毁：让bean实现DisposableBean接口，重写destroy()方法，定义IOC容器关闭前，bean的销毁逻辑
 *      3. 使用JSR250协议：
 *          被@PostConstruct标注的bean的方法：方法为初始化方法
 *          被@PreDestroy标注的bean的方法：方法为销毁方法
 *      4. BeanPostProcessor接口：bean的后置（bean初始化方法执行前后）处理器
 *           bean初始化方法执行前后进行一些逻辑工作：
 *                  postProcessBeforeInitialization()方法：bean初始化方法执行前 执行此方法
 *                  postProcessAfterInitialization()方法：bean初始化方法执行后 执行此方法
 *         spring底层对BeanPostProcessor的使用：
 *              bean属性赋值、注入其他组件、@Autowired、@PostConstruct、@PreDestroy、@Async等等
 */
@Configuration
@ComponentScan(value = {"com.ljw"},excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {MyConfig.class}),
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
public class ConfigOfBeanLifeCycle {

    @Autowired
    Color color;


    @Scope(value = "prototype")
    @Bean(value = "color",initMethod = "init",destroyMethod = "destroy")
    public Color getColor(){
        return new Color("red");
    }


    @Bean(value = {"car"},initMethod = "init",destroyMethod = "destroy")
    public Car getCar(){
        //单实例时，结果为true，表明getColor()和color是IOC容器中的同一个实例对象
        //多实例时，结果false，表明在每次需要bean实例时才创建
        System.out.println(color==getColor());
        //return new Car(4.5,getColor());//getColor()方法可以获取IOC容器中的实例color
        return new Car(4.5,color);//@Autowired将IOC容器中的实例color作为属性注入 至 本类
    }

    @Bean("bike")
    public Bike getBike(){
        System.out.println("创建黑马自行车实例");
        return new Bike("黑马自行车");
    }


    @Bean("desk")
    public Desk getDesk(){
        System.out.println("创建木制桌子实例");
        return new Desk("木制桌子");
    }

    @Bean(value = {"boat"})
    public Boat getBoat(){
        return new Boat();
    }
}
